package com.alibaba.cirtus.ots.application.adapter.ability.facade.service.sap;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import com.alibaba.cirtus.ots.application.adapter.ability.facade.serviceV2.sap.MnSapIf004V2ServiceImpl;
import com.alibaba.cirtus.ots.application.adapter.ability.model.request.ModifyOrderLineRequest;
import com.alibaba.cirtus.ots.application.adapter.ability.model.request.ModifyOrderRequest;
import com.alibaba.cirtus.ots.application.adapter.ability.utils.CodeUtil;
import com.alibaba.cirtus.ots.application.adapter.ability.utils.ResponseUtil;
import com.alibaba.citrus.ots.common.annotation.ProcessInvoker;
import com.alibaba.citrus.ots.common.util.IntegrateUtils;
import com.alibaba.citrus.ots.common.util.SapAndCrmFieldDealUtils;
import com.alibaba.citrus.ots.common.util.TimeUtil;
import com.alibaba.cz.base.tool.Nullable;
import com.alibaba.cz.base.tool.log.Log;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.lattice2.epoch.middleware.cache.runtime.service.EpochCacheService;
import com.alibaba.lattice2.epoch.sdk.model.Result;

import com.epoch.app.bcots.contants.BcOtsConstants;
import com.epoch.app.bcots.model.dto.*;
import com.epoch.app.bcots.service.BaseDataService;
import com.epoch.app.bcots.service.UnifiedInventoryService;
import com.epoch.app.otsapplicationadaptersdk.materialsyncretry.model.MaterialSyncRetry;
import com.epoch.app.otsapplicationadaptersdk.materialsyncretry.service.MaterialSyncRetryService;
import com.epoch.app.otsapplicationadaptersdk.model.dto.MaterialSyncRetryLoadListRequest;
import com.epoch.app.otsapplicationadaptersdk.model.dto.SapRetrySaveRequest;
import com.epoch.app.otsapplicationadaptersdk.model.enums.RetryStatus;
import com.epoch.app.otsapplicationadaptersdk.model.enums.SapApiCode;
import com.epoch.app.otsapplicationadaptersdk.sap.MnSapCommDetail;
import com.epoch.app.otsapplicationadaptersdk.sap.MnSapCommResponse;
import com.epoch.app.otsapplicationadaptersdk.sap.MnSapCommSDO;
import com.epoch.app.otsapplicationadaptersdk.sap.MnSapIf004Request;
import com.epoch.app.otsapplicationadaptersdk.sap.MnSapIf015Detail;
import com.epoch.app.otsapplicationadaptersdk.sap.MnSapIf015Request;
import com.epoch.app.otsapplicationadaptersdk.sap.MnSapIf015SDO;
import com.epoch.app.otsapplicationadaptersdk.sap.mnsapif015.service.MnSapIf015Service;
import com.epoch.app.otsapplicationadaptersdk.sapretrywrite.service.SapRetryWriteService;
import com.epoch.app.otsapplicationadaptersdk.sapv2.mnsapif004v2.service.MnSapIf004V2Service;
import com.epoch.app.otsb2btradecenter.api.orderwrite.service.OrderWriteService;
import com.epoch.app.otsforecastsales.api.forecastorderlinequery.service.ForecastOrderLineQueryService;
import com.epoch.app.otsforecastsales.model.dto.ActivitySDO;
import com.epoch.app.otsforecastsales.model.dto.QuerySaleUnitRequest;
import com.epoch.app.otsforecastsales.model.dto.SelectCombox;
import com.epoch.app.otsplatformenhance.api.customeraddressquery.service.CustomerAddressQueryService;
import com.epoch.app.otsplatformenhance.api.group.scitemgroupquery.service.ScItemGroupQueryService;
import com.epoch.app.otsplatformenhance.api.organizationquery.service.OrganizationQueryService;
import com.epoch.app.otsplatformenhance.api.scitemquery.service.ScItemQueryService;
import com.epoch.app.otsplatformenhance.dto.request.IdQueryRequest;
import com.epoch.app.otsplatformenhance.dto.request.QueryAddressRequest;
import com.epoch.app.otsplatformenhance.dto.request.QueryScItemGroupRequest;
import com.epoch.app.otsplatformenhance.dto.response.ScItemGroupResponse;
import com.epoch.app.otsplatformenhance.interfacedatasyncconfigquery.service.InterfaceDataSyncConfigQueryService;
import com.epoch.app.otsplatformenhance.model.dto.DataCheckRequest;
import com.epoch.app.otsplatformenhance.model.dto.PageQueryAddressListRequest;
import com.epoch.app.otsplatformenhance.model.dto.PageQueryAddressListResponse;
import com.epoch.app.otsplatformenhance.model.enums.OrderTypeEnum;
import com.epoch.app.otsplatformenhance.sdo.CustomerAddressSDO;
import com.epoch.app.otsplatformenhance.service.OtsPlatformEnhanceService;
import com.epoch.app.otspricecenter.api.creditquery.service.CreditQueryService;
import com.epoch.app.otspricecenter.model.dto.CreditReponse;
import com.epoch.app.otspricecenter.model.dto.QueryCreditRequest;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

@Component
public class MnSapIf015ServiceImpl implements MnSapIf015Service {

    private static final Log log = Log.getLogger(MnSapIf015ServiceImpl.class);

    @Autowired
    private BaseDataService baseDataService;
    @Autowired
    private CustomerAddressQueryService customerAddressQueryService;
    @Autowired
    private ScItemGroupQueryService scItemGroupQueryService;
    @Autowired
    private ScItemQueryService scItemQueryService;
    @Autowired
    private UnifiedInventoryService unifiedInventoryService;
    @Autowired
    private ForecastOrderLineQueryService forecastOrderLineQueryService;
    @Autowired
    private CreditQueryService creditQueryService;
    @Autowired
    private OtsPlatformEnhanceService otsPlatformEnhanceService;
    @Autowired
    private InterfaceDataSyncConfigQueryService interfaceDataSyncConfigQueryService;
    @Autowired
    private OrganizationQueryService organizationQueryService;
    @Resource
    OrderWriteService orderWriteService;
    @Resource
    SapRetryWriteService sapRetryWriteService;
    @Resource
    EpochCacheService epochCacheService;

    @Resource
    private MaterialSyncRetryService materialSyncRetryService;
    @Resource(type = MnSapIf004V2ServiceImpl.class)
    private MnSapIf004V2Service mnSapIf004V2Service;
    private static final Integer MAX_PAGE_SIZE = 1000;
    private static final String SALES_ORDER_CACHE_KEY = "SALES_ORDER_CACHE_KEY_";
    //设置sap过期时间为
    private static final Long SAP_TIMESTAMP_CACHE_EXPIRE = 60 * 60 * 24 * 100L;
    @Value("${ots.checkTimestamp:0}")
    private boolean checkTimestamp;

//    private static ScheduledExecutorService executorService = Executors.newScheduledThreadPool(8);


    @ProcessInvoker(remark = "MnSapIf015Service", errorCode = "", printLog = true)
    @Override
    public MnSapCommResponse externalSyncSaleOrder(MnSapIf015Request mnSapIf015Request) {
        log.info("MnSapIf015Request mnSapIf015Request:" + JSONObject.toJSONString(mnSapIf015Request));
        MnSapCommResponse response = new MnSapCommResponse();
        List<MnSapCommSDO> mnSapCommSDOS = new ArrayList<>();
        MnSapCommSDO mnSapCommSDO = new MnSapCommSDO();
        //2022.10.19 sap报文里的订单id转换成内部主键id  sap: 1开头 中间补0  总长度10
        mnSapIf015Request.getData().setTradeOrderId(CodeUtil.convertTradeOrderId(mnSapIf015Request.getData().getTradeOrderId()));
        mnSapCommSDO.setHeaderKey(mnSapIf015Request.getData().getHeaderKey());
        mnSapCommSDO.setExtId(mnSapIf015Request.getData().getTradeOrderId());
        response.setInterfacePath(mnSapIf015Request.getMessageHeader().getInterfacePath());
        response.setMessageId(mnSapIf015Request.getMessageHeader().getMessageId());

        ModifyOrderRequest request = new ModifyOrderRequest();
        MnSapIf015SDO data = mnSapIf015Request.getData();

        // Try to get from mogodb if null
        if (data == null) {
            data = IntegrateUtils.safeGetMessageData(MnSapIf015SDO.class);
        }

        //根据配置表进行数据拦截过滤
        DataCheckRequest dataCheckRequest = new DataCheckRequest();
        dataCheckRequest.setOrderType(OrderTypeEnum.SALEORDER.getCode());
        dataCheckRequest.setChannelOutCode(data.getSapChannel());
        dataCheckRequest.setOrgOutCode(data.getSaleOrganizationCode());
        dataCheckRequest.setVariable(SapAndCrmFieldDealUtils.toDateString(data.getCreateDate()));
        Result<Boolean> checkResult = interfaceDataSyncConfigQueryService.dataCheck(dataCheckRequest);
        if (checkResult != null && checkResult.getResult() != null && !checkResult.getResult()) {
            log.info("interfaceDataSyncConfigQueryService 拦截 " + data.getTradeOrderId() + " " + data.getOutOrderId());
            mnSapCommSDO.setStatus("S");
            mnSapCommSDO.setMessage("成功");
            mnSapCommSDOS.add(mnSapCommSDO);
            response.setData(mnSapCommSDOS);
            return response;
        }
        request.setTradeOrderId(data.getTradeOrderId());
        request.setOutOrderId(SapAndCrmFieldDealUtils.generateIdField(data.getOutOrderId()));
        request.setOrderType(data.getOrderType());
        request.setCreditCheckStatus(data.getExt());
        //sap销售组织信息->平台
        List<String> outCodes = new ArrayList<>();
        outCodes.add(data.getSaleOrganizationCode());
        BaselineGetOrganizationByOutCodes2Request byOutCodes2Request = new BaselineGetOrganizationByOutCodes2Request();
        byOutCodes2Request.setOutCodes(outCodes);
        byOutCodes2Request.setStatus(1);
//        Map saleOrgMap = externalSyncSaleOrder$getOrganizationByOutCodes(outCodesRequest);
        BaselineGetOrganizationByOutCodes2Response byOutCodes2Response = baseDataService.baselineGetOrganizationByOutCodes2(byOutCodes2Request);

//        JSONArray saleJsonArray = JSONObject.parseObject(JSONObject.toJSONString(saleOrgMap)).getJSONArray("result");
        if (byOutCodes2Response == null || CollectionUtils.isEmpty(byOutCodes2Response.getResult())) {
            mnSapCommSDO.setStatus("E");
            mnSapCommSDO.setMessage("销售组织转换失败");
            mnSapCommSDO.setErrCode("OTS-05-001-10-16-049");
            mnSapCommSDOS.add(mnSapCommSDO);
            response.setData(mnSapCommSDOS);
            log.error("MnSapIf015Service.externalSyncSaleOrder error: " + JSON.toJSONString(response));
            saveSapRetry(mnSapIf015Request,"销售组织转换失败");
            return response;
        }

        Map<String, OrganizationSDO> organizationSDOMap = byOutCodes2Response.getResult().stream().collect(Collectors.toMap(OrganizationSDO::getOutCode, org -> org, (k1, k2) -> k2));
        if (organizationSDOMap.get(data.getSaleOrganizationCode()) != null) {
            OrganizationSDO organizationSDO = organizationSDOMap.get(data.getSaleOrganizationCode());
            request.setSaleOrganizationCode(organizationSDO.getId());
            request.setSaleOrganizationName(organizationSDO.getName());
        } else {
            mnSapCommSDO.setStatus("E");
            mnSapCommSDO.setMessage("销售组织转换失败");
            mnSapCommSDO.setErrCode("OTS-05-001-10-16-049");
            mnSapCommSDOS.add(mnSapCommSDO);
            response.setData(mnSapCommSDOS);
            log.error("MnSapIf015Service.externalSyncSaleOrder error: " + JSON.toJSONString(response));
            saveSapRetry(mnSapIf015Request,"销售组织转换失败");
            return response;
        }

        //sap业务渠道->平台
        BaselineQueryChannelByPageRequest channelByPageRequest = new BaselineQueryChannelByPageRequest();
        channelByPageRequest.setOutCode(data.getSapChannel());
//        Map map = externalSyncSaleOrder$baselineQueryChannel(channelByPageRequest);
        Map map = (Map) baseDataService.baselineQueryChannelByPage(channelByPageRequest);
        JSONObject jsonMap = JSONObject.parseObject(JSONObject.toJSONString(map));
        JSONArray jsonArray = jsonMap.getJSONObject("result").getJSONArray("content");
        if (CollectionUtils.isEmpty(jsonArray)) {
            mnSapCommSDO.setStatus("E");
            mnSapCommSDO.setMessage("业务渠道转换失败");
            mnSapCommSDO.setErrCode("999");
            mnSapCommSDOS.add(mnSapCommSDO);
            response.setData(mnSapCommSDOS);
            log.error("MnSapIf015Service.externalSyncSaleOrder error: " + JSON.toJSONString(response));
            saveSapRetry(mnSapIf015Request,"业务渠道转换失败");
            return response;
        }
        JSONObject jsonObject1 = jsonArray.getJSONObject(0);
        request.setSapChannel(jsonObject1.getString("channelCode"));
        request.setSapChannelName(jsonObject1.getString("channelName"));

        //sap货品组编码->平台
        /*QueryScItemGroupRequest scItemGroupRequest = new QueryScItemGroupRequest();
        scItemGroupRequest.setCode(data.getProductGroupCode());
        PageQueryScItemGroupListResponse scItemGroupListResponse = externalSyncSaleOrder$queryScItemGroup(scItemGroupRequest);*/
        QueryScItemGroupRequest scItemGroupRequest = new QueryScItemGroupRequest();
        Result<ScItemGroupResponse> scItemGroup = scItemGroupQueryService.getScItemGroup(scItemGroupRequest);
        if (scItemGroup.getResult() == null) {
            mnSapCommSDO.setStatus("E");
            mnSapCommSDO.setMessage("货品组编码转换失败");
            mnSapCommSDO.setErrCode("999");
            mnSapCommSDOS.add(mnSapCommSDO);
            response.setData(mnSapCommSDOS);
            log.error("MnSapIf015Service.externalSyncSaleOrder error: " + JSON.toJSONString(response));
            saveSapRetry(mnSapIf015Request,"货品组编码转换失败");
            return response;
        }
        request.setProductGroupCode(scItemGroup.getResult().getCode());
        request.setProductGroupName(scItemGroup.getResult().getName());

        request.setCreator(data.getCreator());
        request.setModifier(data.getModifier());
        request.setCreateDate(SapAndCrmFieldDealUtils.toDateString(data.getCreateDate()));
        request.setCreateTime(SapAndCrmFieldDealUtils.toDateString(data.getCreateTime()));
        request.setGmtModified(SapAndCrmFieldDealUtils.toDateString(data.getGmtModified()));
        request.setBeginTime(SapAndCrmFieldDealUtils.toDateString(data.getBeginTime()));


        //sap客户编码、客户收货地址编码->平台
        PageQueryAddressListRequest pageQueryAddressListRequest = new PageQueryAddressListRequest();
        pageQueryAddressListRequest.setAddressCode(data.getDeliveryPartCode());
        pageQueryAddressListRequest.setCustomerCode(data.getSoldPartCode());
        pageQueryAddressListRequest.setOrgSaleOrganizationCode(request.getSaleOrganizationCode());
        pageQueryAddressListRequest.setChannelCode(request.getSapChannel());
        pageQueryAddressListRequest.setItemGroup(data.getProductGroupCode());

        PageQueryAddressListResponse listResult = otsPlatformEnhanceService.pageQueryAddressList(pageQueryAddressListRequest);
        if (CollectionUtils.isEmpty(listResult.getResult())) {
            mnSapCommSDO.setStatus("E");
            mnSapCommSDO.setMessage("客户编码、收货地址转换失败");
            mnSapCommSDO.setErrCode("999");
            mnSapCommSDOS.add(mnSapCommSDO);
            response.setData(mnSapCommSDOS);
            log.error("MnSapIf015Service.externalSyncSaleOrder error: " + JSON.toJSONString(response));
            saveSapRetry(mnSapIf015Request,"客户编码、收货地址转换失败");
            return response;
        }
        List<CustomerAddressSDO> collectAddressList = listResult.getResult().stream().filter(customerAddressSDO ->
                org.apache.commons.lang.StringUtils.isNotBlank(customerAddressSDO.getPrincipal())
        ).collect(Collectors.toList());

        if (CollectionUtils.isEmpty(collectAddressList)) {
            mnSapCommSDO.setStatus("E");
            mnSapCommSDO.setMessage("客户送达方没有分派销售负责人");
            mnSapCommSDO.setErrCode("999");
            mnSapCommSDOS.add(mnSapCommSDO);
            response.setData(mnSapCommSDOS);
            log.error("MnSapIf015Service.externalSyncSaleOrder error: " + JSON.toJSONString(response));
            saveSapRetry(mnSapIf015Request,"客户送达方没有分派销售负责人");
            return response;
        }

        CustomerAddressSDO customerAddressSDO = collectAddressList.get(0);
        request.setSoldPartCode(customerAddressSDO.getCustomerCode());
        request.setSoldPartName(customerAddressSDO.getCustomerName());
        request.setDeliveryPartCode(customerAddressSDO.getAddressCode());
        request.setDeliveryPartName(customerAddressSDO.getAddressName());
        request.setContactor(customerAddressSDO.getContactName());
        request.setContactorPhone(customerAddressSDO.getCellphoneNumber());
        request.setSaleDepartmentCode(customerAddressSDO.getOrgSaleDepartmentCode());
        request.setSaleDepartmentName(customerAddressSDO.getOrgSalesDepartmentName());
        request.setSaleChannelCode(customerAddressSDO.getOrgSaleChannelCode());
        request.setSaleChannelName(customerAddressSDO.getOrgSalesChannelName());
        request.setBisUnitCode(customerAddressSDO.getOrgBussinessUnitCode());
        //查询部门名称
        if (StringUtils.isEmpty(customerAddressSDO.getOrgSaleDepartmentCode())) {
            log.info("MnSapIf015Service.externalSyncSaleOrder:客户送达方未关联销售部门信息");
        } else {
            IdQueryRequest idQueryRequest = new IdQueryRequest();
            idQueryRequest.setId(customerAddressSDO.getOrgSaleDepartmentCode());
            Result<com.epoch.app.otsplatformenhance.sdo.OrganizationSDO> organizationSDOResult = organizationQueryService.getOrganizationDetail(idQueryRequest);
            if (organizationSDOResult != null && organizationSDOResult.getResult() != null) {
                request.setSaleDepartmentName(organizationSDOResult.getResult().getName());
            } else {
                log.info("MnSapIf015Service.externalSyncSaleOrder:未查询到销售部门 " + JSON.toJSONString(organizationSDOResult));
            }
        }
        if (StringUtils.isEmpty(customerAddressSDO.getOrgSaleChannelCode())) {
            log.info("MnSapIf015Service.externalSyncSaleOrder:客户送达方未关联销售渠道信息");
        } else {
            IdQueryRequest idQueryRequest = new IdQueryRequest();
            idQueryRequest.setId(customerAddressSDO.getOrgSaleChannelCode());
            Result<com.epoch.app.otsplatformenhance.sdo.OrganizationSDO> organizationSDOResult = organizationQueryService.getOrganizationDetail(idQueryRequest);
            if (organizationSDOResult != null && organizationSDOResult.getResult() != null) {
                request.setSaleChannelName(organizationSDOResult.getResult().getName());
            } else {
                log.info("MnSapIf015Service.externalSyncSaleOrder:未查询到销售渠道 " + JSON.toJSONString(organizationSDOResult));
            }
        }

        request.setExpectedDeliveryTime(SapAndCrmFieldDealUtils.toDate(data.getExpectedDeliveryTime()));
        request.setShipType(data.getShipType());
        request.setRemark(data.getRemark());
        request.setCustomerReferenceNo(data.getCustomerReferenceNo());
        request.setCashCustomerName(data.getCashCustomerName());
        request.setCostCenter(data.getCostCenter());
        request.setCreateReason(data.getCreateReason());
        request.setPriceTime(SapAndCrmFieldDealUtils.toDateString(data.getPriceTime()));
        request.setFeatures(data.getFeatures());

        mnSapCommSDO.setStatus("S");
        mnSapCommSDO.setMessage("成功");


        if (CollectionUtils.isNotEmpty(data.getItems())) {
            List<MnSapCommDetail> mnSapCommDetails = new ArrayList<>();
            List<ModifyOrderLineRequest> orderLineRequests = new ArrayList<>();
            for (MnSapIf015Detail detail : data.getItems()) {
                MnSapCommDetail mnSapCommDetail = new MnSapCommDetail();
                mnSapCommDetail.setItemKey(detail.getItem_key());

                ModifyOrderLineRequest lineRequest = new ModifyOrderLineRequest();
                lineRequest.setOrderLineId(SapAndCrmFieldDealUtils.generateIdField(detail.getOrderLineId()));
                lineRequest.setOutOrderLineId(SapAndCrmFieldDealUtils.generateIdField(detail.getOutOrderLineId()));
                //sap货品->平台

//                QueryScItemRequest queryScItemRequest = new QueryScItemRequest();
//                queryScItemRequest.setOuterId(SapAndCrmFieldDealUtils.generateIdField(detail.getScItemId()));
//                Result<List<ScItemSDO>> scItemList = scItemQueryService.pageQueryScItemList(queryScItemRequest);

                SearchScItemRequest searchScItemRequest = new SearchScItemRequest();
                SearchReqDTO searchReqDTO = new SearchReqDTO();
                List<String> list = new ArrayList<>();
                list.add(SapAndCrmFieldDealUtils.generateScItemIdField(detail.getScItemId()));
                searchReqDTO.setOuterIdList(list);
                searchScItemRequest.setSearchReqDTO(searchReqDTO);
                Result<List<com.epoch.app.bcots.model.dto.ScItemSDO>> scItemList = baseDataService.searchScItem(searchScItemRequest);

                if (scItemList.isSuccess() && CollectionUtils.isNotEmpty(scItemList.getResult())) {
                    ScItemSDO scItemSDO = scItemList.getResult().get(0);

                    lineRequest.setScItemOutCode(scItemSDO.getOuterId());
                    lineRequest.setScItemName(scItemSDO.getTitle());
                    lineRequest.setScItemId(scItemSDO.getScItemId());
                    Map<String, String> features = scItemSDO.getFeatures();
                    if (MapUtils.isNotEmpty(features)) {
                        String unitName = features.get("unit");
                        String unitCode = features.get("unitName");
                        lineRequest.setCategoryCode(features.get("category"));
                        lineRequest.setCategoryDesc(features.get("categoryDesc"));
                        lineRequest.setCategoryChildCode(features.get("categoryChildCode"));
                        lineRequest.setCategoryChildDesc(features.get("categoryChildDesc"));
                        if (StringUtils.isNotBlank(unitName)) {
                            lineRequest.setInventoryUnit(unitName);
                        }
                        if (StringUtils.isNotBlank(unitCode)) {
                            lineRequest.setInventoryUnitCode(unitCode);
                        }
                    }
                    //todo 接口未取到库存单位名称
//                        build.setInventoryUnitCode(scItemSDO.getUnit());
//                        build.setInventoryUnit(scItemSDO.getUnit());
                    QuerySaleUnitRequest querySaleUnitRequest = QuerySaleUnitRequest.builder().scItemId(scItemSDO.getScItemId()).build();
                    querySaleUnitRequest.setInventoryUnit(lineRequest.getInventoryUnit());
                    querySaleUnitRequest.setInventoryUnitCode(lineRequest.getInventoryUnitCode());
                    querySaleUnitRequest.setUnitConvert("1");
                    Result<List<SelectCombox>> querySaleUnitList = forecastOrderLineQueryService.querySaleUnitList(querySaleUnitRequest);
                    if (querySaleUnitList.isSuccess() && Objects.nonNull(querySaleUnitList.getResult())) {
                        List<SelectCombox> result = querySaleUnitList.getResult();
                        Map<String, SelectCombox> unitMap = new HashMap<>();
                        Nullable.stream(result).forEach(t -> {
                            unitMap.put(t.getValue(), t);
                        });
                        SelectCombox selected = unitMap.get(detail.getSaleUnit());
                        if (selected != null) {
                            lineRequest.setSaleUnitName(selected.getLabel());
                            lineRequest.setUnitConvert(selected.getExt());
                        }

                        SelectCombox inventoryMap = unitMap.get(detail.getSaleUnit());
                        if (inventoryMap != null) {
                            lineRequest.setInventoryUnit(inventoryMap.getLabel());
//                                build.setUnitConvert(inventoryMap.getExt());
                        }
//                            build.setInventoryUnit(map1.get(scItemSDO.getUnit()));
                    }
                }

                if (CollectionUtils.isEmpty(scItemList.getResult())) {
                    log.error("MnSapIf015ServiceImpl_scItemConvertError:{}",detail.getScItemId());
                    List<MnSapCommDetail> commDetails = new ArrayList<>();
                    mnSapCommSDO.setStatus("E");
                    mnSapCommSDO.setMessage("货品编码转换失败");
                    mnSapCommDetail.setStatus("E");
                    mnSapCommDetail.setMessage("货品编码转换失败");
                    commDetails.add(mnSapCommDetail);
                    mnSapCommSDO.setItem(commDetails);
                    mnSapCommSDOS.add(mnSapCommSDO);
                    response.setData(mnSapCommSDOS);
                    log.error("MnSapIf015Service.externalSyncSaleOrder error: " + JSON.toJSONString(response));
                    saveSapRetry(mnSapIf015Request,"货品编码转换失败");
                    return response;
                }

                lineRequest.setQuantity(SapAndCrmFieldDealUtils.toInteger(detail.getQuantity()));
                lineRequest.setSaleUnit(detail.getSaleUnit());
                lineRequest.setPrice(extracted(detail.getPrice()));
                lineRequest.setActivityPrice(extracted(detail.getActivityPrice()));
                lineRequest.setSubTotalAmount(extracted(detail.getSubTotalAmount()));
                lineRequest.setReturnFlag(detail.getReturnFlag());
                lineRequest.setCloseCode(detail.getCloseCode());
                lineRequest.setCloseReason(detail.getCloseReason());
                lineRequest.setGiftActivityId(detail.getGiftActivityId());
                lineRequest.setGiftPromotionId(detail.getGiftPromotionId());
                lineRequest.setGiftFlag(detail.getGiftFlag());
                lineRequest.setSpecialActivityId(detail.getSpecialActivityId());
                lineRequest.setSpecialPromotionId(detail.getSpecialPromotionId());
                lineRequest.setActivityId(detail.getActivityId());
                lineRequest.setManualPromotionId(detail.getManualPromotionId());

                lineRequest.setTurningPrice(extracted(detail.getTurningPrice()));
                lineRequest.setDctBeforePrice(extracted(detail.getDctBeforePrice()));
                lineRequest.setDiscount(detail.getDiscount().trim());
                lineRequest.setNkPrice(extracted(detail.getNkPrice()));

                lineRequest.setShipPoint(detail.getShipPoint());
                lineRequest.setActOccFee(detail.getExt() != null ? String.valueOf(detail.getExt().multiply(new BigDecimal(100))) : null);
                lineRequest.setActOccQty(detail.getExt1() != null ? String.valueOf(detail.getExt1().multiply(new BigDecimal(100))) : null);

                WmsQueryWarehouseZoneListRequest warehouseZoneListRequest = new WmsQueryWarehouseZoneListRequest();
                warehouseZoneListRequest.setSapFactoryCode(detail.getFactoryCode());
                warehouseZoneListRequest.setWarehouseCode(detail.getInventoryCode());
                WmsQueryWarehouseZoneListResponse warehouseZoneList = unifiedInventoryService.wmsQueryWarehouseZoneList(warehouseZoneListRequest);
                if (CollectionUtils.isNotEmpty(warehouseZoneList.getResult())) {
                    WarehouseInfo warehouseInfo = warehouseZoneList.getResult().get(0);
                    lineRequest.setWarehouseCode(warehouseInfo.getId());
                    lineRequest.setWarehouseName(warehouseInfo.getName());
                }
                lineRequest.setFactoryCode(detail.getFactoryCode());
                lineRequest.setInventoryCode(detail.getInventoryCode());

                //add by 皓晖 at 20211217 for 015接口中增加行明细备注字段 begin
                lineRequest.setRemark(detail.getExt2());
                lineRequest.setExt3(detail.getExt3());
                lineRequest.setExt4(detail.getExt4());
                lineRequest.setExt5(detail.getExt5());
                lineRequest.setExt6(detail.getExt6());
                //add by 皓晖 at 20211217 for 015接口中增加行明细备注字段 end

                //20220112 活动参数构建
                StringBuilder sb = new StringBuilder();

                List<ActivitySDO> activitySDOS = new ArrayList<>();
                if (detail.getGiftPromotionId() != null) {
                    ActivitySDO activitySDO = new ActivitySDO();
                    activitySDO.setActivityTermid(detail.getGiftPromotionId());
                    activitySDO.setActivityCode(detail.getGiftActivityId());
                    activitySDO.setActivityfee(converterActivityPrice(detail.getActivityPrice()));
                    activitySDOS.add(activitySDO);
                    sb.append(detail.getGiftActivityId()).append("/");
                }
                if (detail.getSpecialPromotionId() != null) {
                    ActivitySDO activitySDO = new ActivitySDO();
                    activitySDO.setActivityTermid(detail.getSpecialPromotionId());
                    activitySDO.setActivityCode(detail.getSpecialActivityId());
                    activitySDO.setActivityfee(converterActivityPrice(detail.getActivityPrice()));
                    activitySDOS.add(activitySDO);
                    sb.append(detail.getSpecialActivityId()).append("/");
                }
                if (detail.getManualPromotionId() != null) {
                    ActivitySDO activitySDO = new ActivitySDO();
                    activitySDO.setActivityTermid(detail.getManualPromotionId());
                    activitySDO.setActivityCode(detail.getActivityId());
                    activitySDO.setActivityfee(converterActivityPrice(detail.getActivityPrice()));
                    activitySDOS.add(activitySDO);
                    sb.append(detail.getSpecialActivityId()).append("/");
                }
                if (sb.length() > 0) {
                    String s = sb.toString();
                    lineRequest.setActivityCode(s.substring(0, s.length() - 1));
                }

                lineRequest.setActivityFeature(JSON.toJSONString(activitySDOS));

                orderLineRequests.add(lineRequest);

                mnSapCommDetail.setStatus("S");
                mnSapCommDetail.setMessage("成功");
                mnSapCommDetails.add(mnSapCommDetail);
            }
            mnSapCommSDO.setItem(mnSapCommDetails);
            request.setModifyOrderLineRequests(orderLineRequests);

            //查询客户账款
            QueryCreditRequest queryCreditRequest = new QueryCreditRequest();
            queryCreditRequest.setOrganizationCode(request.getSaleOrganizationCode());
            queryCreditRequest.setChannelCode(request.getSapChannel());
            queryCreditRequest.setItemGroupCode(request.getProductGroupCode());
            queryCreditRequest.setCustomerCode(request.getSoldPartCode());
            Result<CreditReponse> result = creditQueryService.queryCreditBalance(queryCreditRequest);
            if (result.getResult() != null) {
                request.setCustomerAccounts(result.getResult().getBalance());
            }
        }
        log.info("request:" + request);

        if (checkTimestamp){
            //校验时间戳格式
            String check = ResponseUtil.check(mnSapIf015Request.getData().getExt1());
            if (StringUtils.isNotBlank(check)){
//                saveSapRetry(mnSapIf015Request,check);
                mnSapCommSDO.setStatus("E");
                mnSapCommSDO.setMessage(check);
                mnSapCommSDO.setErrCode("999");
                if (CollectionUtils.isNotEmpty(data.getItems())){
                    List<MnSapCommDetail> mnSapCommDetails = new ArrayList<>();
                    for (MnSapIf015Detail item : data.getItems()) {
                        MnSapCommDetail mnSapCommDetail = new MnSapCommDetail();
                        mnSapCommDetail.setItemKey(item.getItem_key());
                        mnSapCommDetail.setStatus("E");
                        mnSapCommDetail.setMessage(check);
                        mnSapCommDetails.add(mnSapCommDetail);
                    }
                    mnSapCommSDO.setItem(mnSapCommDetails);
                }
                mnSapCommSDOS.add(mnSapCommSDO);
                response.setData(mnSapCommSDOS);
                log.error("MnSapIf015Service.externalSyncSaleOrder error: " + JSON.toJSONString(response));
                return response;
            }
            //在这里判断时间戳 2022.05.24
            if (!checkModifierTime(mnSapIf015Request.getData())){
                //失败放入重试表
                saveSapRetry(mnSapIf015Request,"当前修改时间早于上一次 不允许更新");
                mnSapCommSDO.setStatus("E");
                mnSapCommSDO.setMessage("当前修改时间早于上一次 不允许更新");
                mnSapCommSDO.setErrCode("999");
                if (CollectionUtils.isNotEmpty(data.getItems())){
                    List<MnSapCommDetail> mnSapCommDetails = new ArrayList<>();
                    for (MnSapIf015Detail item : data.getItems()) {
                        MnSapCommDetail mnSapCommDetail = new MnSapCommDetail();
                        mnSapCommDetail.setItemKey(item.getItem_key());
                        mnSapCommDetail.setStatus("E");
                        mnSapCommDetail.setMessage("当前修改时间早于上一次 不允许更新");
                        mnSapCommDetails.add(mnSapCommDetail);
                    }
                    mnSapCommSDO.setItem(mnSapCommDetails);
                }
                mnSapCommSDOS.add(mnSapCommSDO);
                response.setData(mnSapCommSDOS);
                log.error("MnSapIf015Service.externalSyncSaleOrder error: " + JSON.toJSONString(response));
                return response;
            }else{
//                cache(mnSapIf015Request.getData().getOutOrderId(),mnSapIf015Request.getData().getExt1());
            }
        }

        //2022.05.23 定时任务运行时 callAPI 会引发不可预占的问题 这里给它换成普通的调用
//        externalSyncSaleOrder$callAPI(request);
        com.epoch.app.otsb2btradecenter.dto.request.ModifyOrderRequest modifyOrderRequest =
            JSON.parseObject(JSON.toJSONString(request), com.epoch.app.otsb2btradecenter.dto.request.ModifyOrderRequest.class);
        //因为fastjson转换是时间戳 这边需要转成符合接口入参的yyyy-MM-dd HH:mm:ss
        modifyOrderRequest.setExpectedDeliveryTime(TimeUtil.convertYYYYMMdd2YYYYMMddHHmmss(mnSapIf015Request.getData().getExpectedDeliveryTime()));
        orderWriteService.modifySaleOrder(modifyOrderRequest);
        //如果需要校验时间戳 放入时间戳
        if (checkTimestamp){
            cache(mnSapIf015Request.getData().getOutOrderId(),mnSapIf015Request.getData().getExt1());
        }

        //重试004
        try {
            retry(data.getOutOrderId(),true);
        }catch (Throwable e){
            log.error("MnSapIf015ServiceImpl_retryError",e);
        }
        mnSapCommSDO.setStatus("S");
        mnSapCommSDO.setMessage("成功");
        mnSapCommSDOS.add(mnSapCommSDO);
        response.setData(mnSapCommSDOS);
        log.info("执行结束");
        return response;
    }

    private static String extracted(String s) {
        if (StringUtils.isBlank(s)) {
            return null;
        }
        BigDecimal val = new BigDecimal(s.trim());
        val = val.multiply(new BigDecimal(100)).setScale(0, RoundingMode.DOWN);
        return val.toString();
    }

    private static Long converterActivityPrice(String s) {
        if (StringUtils.isBlank(s)) {
            return null;
        }
        BigDecimal val = new BigDecimal(s);
        return val.multiply(new BigDecimal(100)).longValue();
    }

    /**
     * 保存sap重试记录
     *
     */
    public void saveSapRetry(MnSapIf015Request request,String message){
        try {
            if (request == null){
                return;
            }
            SapRetrySaveRequest sapRetrySaveRequest = SapRetrySaveRequest.builder()
                    .param(JSON.toJSONString(request))
                    .msg(message)
                    .messageId(request.getMessageHeader().getMessageId())
                    .apiCode(SapApiCode.SAP015.getValue())
                    .outKey(request.getData().getOutOrderId())
                    .status(RetryStatus.FAIL.getValue())
                    .requestTime(request.getData().getExt1())
                    .build();
            sapRetryWriteService.save(sapRetrySaveRequest);
        }catch (Throwable e){
            log.error("sapRetrySaveError",e);
        }
    }

    boolean checkModifierTime(MnSapIf015SDO sdo){
        String modifierTime = epochCacheService.get(BcOtsConstants.REDIS_CACHE_CODE(),
                SALES_ORDER_CACHE_KEY + sdo.getOutOrderId());
        String ext = sdo.getExt1();
        if (StringUtils.isNotBlank(modifierTime)){
            String[] modifierTimeArray = modifierTime.split("\\.");
            String[] extArray = ext.split("\\.");
            if (Long.parseLong(modifierTimeArray[0]) > Long.parseLong(extArray[0])) {
                return false;
            } else if (Long.valueOf(modifierTimeArray[0]).longValue() == Long.valueOf(extArray[0]).longValue()) {
                if (Long.parseLong(modifierTimeArray[1]) >= Integer.valueOf(extArray[1]).longValue()) {
                    return false;
                }
            }
        }
        return true;
    }
    void cache(String key,String time){
        if (StringUtils.isAnyBlank(key,time)){
            return;
        }
        epochCacheService.put(BcOtsConstants.REDIS_CACHE_CODE(),
                SALES_ORDER_CACHE_KEY + key,time,
                SAP_TIMESTAMP_CACHE_EXPIRE,
                TimeUnit.SECONDS);
    }


    //重试004先于调拨单的物料凭证
    private void retry(String outAllocateOrderId,boolean canRetry){
        if (!canRetry){
            return;
        }
        MaterialSyncRetryLoadListRequest materialSyncRetryLoadListRequest = new MaterialSyncRetryLoadListRequest();
        materialSyncRetryLoadListRequest.setOutOrderId(outAllocateOrderId);
        materialSyncRetryLoadListRequest.setStatus(0);
        materialSyncRetryLoadListRequest.setLimit(MAX_PAGE_SIZE);
        Result<List<MaterialSyncRetry>> listResult = materialSyncRetryService.loadList(materialSyncRetryLoadListRequest);
        if (listResult != null && CollectionUtils.isNotEmpty(listResult.getResult())){
            for (MaterialSyncRetry materialSyncRetry : listResult.getResult()) {
                try {
                    MnSapIf004Request mnSapIf004Request = JSON.parseObject(materialSyncRetry.getRequestParams(),MnSapIf004Request.class);
                    //延迟执行 防止库存没有占用上
                    MnSapCommResponse response = mnSapIf004V2Service.externalSyncMaterial(mnSapIf004Request);
                    log.info("MnSapIf015ServiceImpl_retry_result:{}",JSON.toJSONString(response));
//                    executorService.schedule(()->{
//                    },5,TimeUnit.SECONDS);
//                    mnSapIf004V2Service.externalSyncMaterial(mnSapIf004Request);
                }catch (Throwable e){
                    log.error("MnSapIf015ServiceImpl_retry",e);
                    log.error("MnSapIf015ServiceImpl_retry,request:{},004:{}",JSON.toJSONString(outAllocateOrderId),JSON.toJSONString(listResult.getResult()));
                }
                continue;
            }
        }
    }

}
